package com.lnsystem.service.impl;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.math.NumberUtils;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lnsystem.constants.LNSystemConstants;
import com.lnsystem.dao.StockDao;
import com.lnsystem.model.Stock;
import com.lnsystem.model.StockRating;
import com.lnsystem.model.stockchekup.ibd.D;
import com.lnsystem.model.stockchekup.ibd.ETablesDataList;
import com.lnsystem.model.stockchekup.ibd.IBDStockCheckup;
import com.lnsystem.service.StockCheckService;

@Component
public class StockCheckServiceIBDImpl implements StockCheckService {

	private static Logger log = Logger.getLogger(StockCheckServiceIBDImpl.class);
	
	@Autowired
	StockDao stockDao;
	
	@Override
	public void checkStock(List<Stock> stockList) {
		
		String healthString="";
		StockRating stockRating;
		
		int i = 1;
		for(Stock stock : stockList) {
			log.info("("+(i++)+" of "+stockList.size()+")  checking stock :"+stock.getSymbol());
			
			 
			stockRating = getStockRating(stock.getSymbol());
			if(stockRating.getStockId()!=null) { //null means stock check didn't return anything for this stock.
				stock.setHealthString(stockRating.getHealthString());
				updateStockRating(stockRating);
			} else {
				log.info("getStockRating() didn't return anything for this stock:"+stock.getSymbol());
			}
			//healthString = checkStock(stock.getSymbol());
			//stock.setHealthString(healthString);
		}
	}
	
	@Override
	public void updateStockRating(StockRating stockRating) {
		if(stockRating != null) {
			//update the stockrating data..
			stockDao.updateStockRatingData(stockRating);
		}
	}
	
	@Override
	public StockRating getStockRating(String symbol) {

		//TODO - change this later to be injected.
		ObjectMapper mapper = new ObjectMapper(); 
		
		Stock stock = stockDao.getStockBySymbol(symbol);
		StockRating stockRating  = stock.getStockRating();
		

		
		if(stockRating!=null && stockRating.getLastUpdateOn()!=null) {
			DateTime lastUpdateOn = new DateTime(stockRating.getLastUpdateOn());
			if(lastUpdateOn.isAfter(DateTime.now().minusDays(LNSystemConstants.DAYS_BEFORE_NEXT_STOCK_CHECK))) { // no need to do check as it was done just less than 15 days ago
				log.info(">> Skipping stock check for : "+stock.getSymbol());
				return stockRating;
			}
		} else {
			stockRating = new StockRating();
		}

		
		
		StringBuilder response = new StringBuilder("");
    	   
    	try {
    		
			String responseAsJSONString = sendGet(symbol);

			log.debug(">>> JSON response string: "+responseAsJSONString);

			
			int sleepTime = getRandomNumberInRange(3,8)*1000;
			
			
			//throttling...
			log.debug("sleeping for "+sleepTime/1000+" seconds...");
			Thread.sleep(sleepTime);
			
			IBDStockCheckup ibdStockCheckupResponse = mapper.readValue(responseAsJSONString, IBDStockCheckup.class);
			
			//Map<String, Object> additionalPropsMap = ibdStockCheckupResponse.getAdditionalProperties();
			
			D d = ibdStockCheckupResponse.getD();
			//Map<String, Object> additionalPropsMap = d.getAdditionalProperties();
			
			List<ETablesDataList> eTablesDataList = d.getETablesDataList();
			for(ETablesDataList eTablesData : eTablesDataList) {
				log.debug(eTablesData.getStockRating());
				response.append(eTablesData.getStockRating());
				log.info(">>> "+eTablesData.getCompRating());
				
				
				populateStockRatingData(eTablesData,stockRating);
				
				
				stockRating.setStockId(stock);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return stockRating;
	}
	
	@Override
	public String checkStock(String symbol) {

		//TODO - change this later to be injected.
		ObjectMapper mapper = new ObjectMapper(); 
		StringBuilder response = new StringBuilder("");
    	   
    	try {
    		
			String responseAsJSONString = sendGet(symbol);

			log.debug(">>> JSON response string: "+responseAsJSONString);
			
			int sleepTime = getRandomNumberInRange(3,8)*1000;
			
			//throttling...
			log.debug("sleeping for "+sleepTime/1000+" seconds...");
			Thread.sleep(sleepTime);
			
			IBDStockCheckup ibdStockCheckupResponse = mapper.readValue(responseAsJSONString, IBDStockCheckup.class);
			
			//Map<String, Object> additionalPropsMap = ibdStockCheckupResponse.getAdditionalProperties();
			
			D d = ibdStockCheckupResponse.getD();
			//Map<String, Object> additionalPropsMap = d.getAdditionalProperties();
			
			List<ETablesDataList> eTablesDataList = d.getETablesDataList();
			for(ETablesDataList eTablesData : eTablesDataList) {
				log.debug(eTablesData.getStockRating());
				response.append(eTablesData.getStockRating());
				log.info(">>> "+eTablesData.getCompRating());
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return response.toString();
	}

   	// HTTP GET request
   	private static String sendGet(String symbol) throws Exception {
    
   		String url = "http://research.investors.com/Services/SiteAjaxService.asmx/GetStockTables?sortcolumn1=%22comprating%22&sortOrder1=%22DESC%22&sortcolumn2=%22%22&sortOrder2=%22DESC%22&filter=%22%22&search=%22"+symbol+"%22";
    
   		URL obj = new URL(url);
   		HttpURLConnection con = (HttpURLConnection) obj.openConnection();
    
   		// optional default is GET
   		con.setRequestMethod("GET");

   		//add request header
   		//con.setRequestProperty("User-Agent", USER_AGENT);
        con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0");
        con.setRequestProperty("Host", "research.investors.com");
        con.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        con.setRequestProperty("Accept-Language", "en-GB,en;q=0.5");
        con.setRequestProperty("Accept-Encoding", "gzip, deflate");
        con.setRequestProperty("Content-Type", "application/json; charset=utf-8");
        con.setRequestProperty("Referer", "http://research.investors.com/etables/default.aspx");
        con.setRequestProperty("Cookie", "s_vnum=1413988645882%26vn%3D4; s_nr=1411398858500; s_vi=[CS]v1|2A101A1285194651-40000606E0000DB7[CE]; BCSI-CS-221576a13e3e6d47=2; ASP.NET_SessionId=ziye5lbr152wamujqkpm3kjh; s_cc=true; s_sq=%5B%5BB%5D%5D; s_invisit=true; QSI_HistorySession=http%3A%2F%2Fwww.investors.com%2Fproducts%2Fpremium-investing-tools%2Fetables%2F~1412010083621%7Chttp%3A%2F%2Fresearch.investors.com%2Fquotes%2Fnasdaq-netflix-inc-nflx.htm%3Ffromsearch%3D1~1412012128324; QSI_SI_b3B9jsfbYnFoklL_intercept=true; pm[sess_r]=; pm[t][quote]=quote01; pm[t][ppg]=http%3A//research.investors.com/quotes/nasdaq-netflix-inc-nflx.htm%3Ffromsearch%3D1; __utma=118341898.1828488415.1412012123.1412012123.1412012123.1; __utmb=118341898.11.8.1412012177802; __utmc=118341898; __utmz=118341898.1412012123.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); pm[p]=9; pm[pe]=false; newsView=IBD; Last5Symbols=NFLX; ExPop=1");
        con.setRequestProperty("Connection", "keep-alive");
        
        
   		int responseCode = con.getResponseCode();
   		log.debug("\nSending 'GET' request to URL : " + url);
   		log.debug("Response Code : " + responseCode);
    
   		BufferedReader in = new BufferedReader(
   		        new InputStreamReader(con.getInputStream()));
   		String inputLine;
   		StringBuffer response = new StringBuffer();
    
   		while ((inputLine = in.readLine()) != null) {
   			response.append(inputLine);
   		}
   		in.close();
    
   		//print result
   		//System.out.println(response.toString());
   		return response.toString();
   	}
   	
   	int getRandomNumberInRange(int min, int max)
   	{
   	   int range = (max - min) + 1;     
   	   return (int)(Math.random() * range) + min;
   	}

   	void populateStockRatingData(ETablesDataList etablesData,StockRating stockRating) {
   		
   		if(stockRating == null) {
   			stockRating =  new StockRating();
   		}
   		
   		stockRating.setAccDis(etablesData.getAccDis());
   		stockRating.setCompDesc(etablesData.getCompDesc());
   		
   		if(etablesData.getCompRating()!="" && NumberUtils.isNumber(etablesData.getCompRating())) {
   	   		stockRating.setCompRating(Integer.parseInt(etablesData.getCompRating()));   			
   		}
   		
   		if(etablesData.getConsecQtrEpsGrt15()!="" && NumberUtils.isNumber(etablesData.getConsecQtrEpsGrt15())) {
   	   		stockRating.setConsecQtrEpsGrt15(Integer.parseInt(etablesData.getConsecQtrEpsGrt15()));
   		}
   		
   		if(etablesData.getCurQtrEpsEstPerChg()!="" && NumberUtils.isNumber(etablesData.getCurQtrEpsEstPerChg())) {
   	   		stockRating.setCurQtrEpsEstPerChg(Double.parseDouble(etablesData.getCurQtrEpsEstPerChg()));
   		}
   		if(etablesData.getCurYrEpsEstPerChg()!="" && NumberUtils.isNumber(etablesData.getCurYrEpsEstPerChg())) {
   	   		stockRating.setCurYrEpsEstPerChg(Double.parseDouble(etablesData.getCurYrEpsEstPerChg()));
   		}
   		if(etablesData.getDailyVol()!="" && NumberUtils.isNumber(etablesData.getDailyVol())) {
   	   		stockRating.setDailyVol(Double.parseDouble(etablesData.getDailyVol()));
   		}
   		
/*   		if(etablesData.getDivYield()!="" && etablesData.getDivYield()!="--") {
   	   		stockRating.setDivYield(Double.parseDouble(etablesData.getDivYield()));
   		}*/
   		
   		if(etablesData.getEPSRank()!="" && NumberUtils.isNumber(etablesData.getEPSRank())) {
   	   		stockRating.setEPSRank(Integer.parseInt(etablesData.getEPSRank()));   			
   		}
   		
   		if(etablesData.getGrpStr()!="" && etablesData.getGrpStr()!="--") {
   	   		stockRating.setGrpStr(etablesData.getGrpStr());   			
   		}
   		
   		if(etablesData.getLastQtrEpsPerChg()!="" && NumberUtils.isNumber(etablesData.getLastQtrEpsPerChg())) {
   	   		stockRating.setLastQtrEpsPerChg(Double.parseDouble(etablesData.getLastQtrEpsPerChg()));
   		}
   		if(etablesData.getLastQtrSalesPerChg()!="" && NumberUtils.isNumber(etablesData.getLastQtrSalesPerChg())) {
   	   		stockRating.setLastQtrSalesPerChg(Double.parseDouble(etablesData.getLastQtrSalesPerChg()));
   		}
   		
   		if(etablesData.getMgmtOwnsPer()!="" && NumberUtils.isNumber(etablesData.getMgmtOwnsPer())) {
   	   		stockRating.setMgmtOwnsPer(Integer.parseInt(etablesData.getMgmtOwnsPer()));
   		}
   		
   		if(etablesData.getPERatio()!="" && NumberUtils.isNumber(etablesData.getPERatio())) {
   	   		stockRating.setpERatio(Double.parseDouble(etablesData.getPERatio()));
   		}
   		
   		if(etablesData.getPerOffHigh()!="" && NumberUtils.isNumber(etablesData.getPerOffHigh())) {
   	   		stockRating.setPerOffHigh(Double.parseDouble(etablesData.getPerOffHigh()));
   		}
   		
   		if(etablesData.getPretaxMargin()!="" && NumberUtils.isNumber(etablesData.getPretaxMargin())) {
   	   		stockRating.setPretaxMargin(Double.parseDouble(etablesData.getPretaxMargin()));
   		}
   		
   		if(etablesData.getPrice()!="" && NumberUtils.isNumber(etablesData.getPrice())) {
   	   		stockRating.setPrice(Double.parseDouble(etablesData.getPrice()));
   		}
   		
   		if(etablesData.getPriceChange()!="" && NumberUtils.isNumber(etablesData.getPriceChange())) {
   	   		stockRating.setPriceChange(Double.parseDouble(etablesData.getPriceChange()));
   		}
   		
   		if(etablesData.getPriceClose()!="" && NumberUtils.isNumber(etablesData.getPriceClose())) {
   	   		stockRating.setPriceClose(Double.parseDouble(etablesData.getPriceClose()));
   		}
   		
   		/*if(!"--".equals(etablesData.getRank())) {
   	   		stockRating.setRank(etablesData.getRank());
   		}*/
   		
   		if(etablesData.getRelSt()!="" && NumberUtils.isNumber(etablesData.getRelSt())) {
   	   		stockRating.setRelSt(Integer.parseInt(etablesData.getRelSt()));
   		}
   		
   		if(etablesData.getROE()!="" && NumberUtils.isNumber(etablesData.getROE())) {
   	   		stockRating.setROE(Double.parseDouble(etablesData.getROE()));
   		}
   		
   		if(etablesData.getSmr()!="" && etablesData.getSmr()!="--") {
   	   		stockRating.setSmr(etablesData.getSmr());
   		}
   		
   		if(etablesData.getSponRating()!="" && etablesData.getSponRating()!="--") {
   	   		stockRating.setSponRating(etablesData.getSponRating());
   		}
   		
   		if(etablesData.getSymbol()!="" && etablesData.getSymbol()!="--") {
   	   		stockRating.setSymbol(etablesData.getSymbol());
   		}
   		
   		if(etablesData.getVolPerChange()!="" && NumberUtils.isNumber(etablesData.getVolPerChange())) {
   	   		stockRating.setVolPerChange(Double.parseDouble(etablesData.getVolPerChange()));
   		}
   		
   		if(etablesData.getWeekHigh52()!="" && NumberUtils.isNumber(etablesData.getWeekHigh52())) {
   	   		stockRating.setWeekHigh52(Double.parseDouble(etablesData.getWeekHigh52()));
   		}
   		
   		if(etablesData.getStockRating()!="" && etablesData.getStockRating()!="--") {
   	   		stockRating.setHealthString(etablesData.getStockRating());
   		}
   		
   		//update lastupdateon datetimestamp
   		stockRating.setLastUpdateOn(DateTime.now().toDate());
   		
   		//return stockRating;
   		
   	}

   	
}
